{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# How to combine colormaps for SatPy?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. `proplot` method (recommended)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's read the file first. You can check the basic tutorial [here](https://github.com/zxdawn/FY-4/blob/master/satpy/examples/FY4A_agri_introduction%28EN%29.ipynb)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "E:\\miniconda3\\envs\\satpy\\lib\\site-packages\\pyproj\\crs.py:562: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems\n",
      "  proj_string = self.to_proj4()\n",
      "E:\\miniconda3\\envs\\satpy\\lib\\site-packages\\pyproj\\crs.py:562: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems\n",
      "  proj_string = self.to_proj4()\n",
      "E:\\miniconda3\\envs\\satpy\\lib\\site-packages\\pyproj\\crs.py:562: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems\n",
      "  proj_string = self.to_proj4()\n"
     ]
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import os, glob\n",
    "from satpy.scene import Scene\n",
    "from trollimage.colormap import greys, spectral\n",
    "\n",
    "# set the config path\n",
    "os.environ['PPP_CONFIG_DIR'] = '../satpy_config/'\n",
    "\n",
    "# load FY4A filenames\n",
    "filenames = glob.glob('../data/FY4A-_AGRI*4000M_V0001.HDF')\n",
    "\n",
    "# create the scene object\n",
    "scn = Scene(filenames, reader='agri_l1')\n",
    "channel = 'C12'\n",
    "scn.load([channel])\n",
    "\n",
    "# resample it to interested region\n",
    "lekima_scene = scn.resample('lekima_4km')\n",
    "img = lekima_scene[channel]\n",
    "\n",
    "# get lon.lat from scene\n",
    "lon, lat = img.attrs['area'].get_lonlats()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's try `cartopy` first:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 1.15 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# %%capture\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import cartopy.crs as ccrs\n",
    "\n",
    "# get projection and set axis\n",
    "crs = img.attrs['area'].to_cartopy_crs()\n",
    "f, ax = plt.subplots(subplot_kw=dict(projection=crs))\n",
    "ax.gridlines()\n",
    "\n",
    "# plot data\n",
    "plt.imshow(img, transform=crs, extent=crs.bounds, origin='upper')\n",
    "\n",
    "# set others\n",
    "cbar = plt.colorbar()\n",
    "cbar.set_label(r'Brightness Temperature ($^\\circ$C)')\n",
    "ax.set_title(img.attrs['long_name'])\n",
    "\n",
    "# f.savefig('./figures/pyplot_crs.jpg')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src='./figures/pyplot_crs.jpg'>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Of course, we can switch to `pcarree` projection:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 1.51 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# %%capture\n",
    "\n",
    "# set axis\n",
    "f, ax = plt.subplots(subplot_kw=dict(projection=ccrs.PlateCarree()))\n",
    "ax.gridlines()\n",
    "\n",
    "# plot data\n",
    "plt.pcolormesh(lon, lat, img, transform=ccrs.PlateCarree())\n",
    "\n",
    "# set others\n",
    "cbar = plt.colorbar()\n",
    "cbar.set_label(r'Brightness Temperature ($^\\circ$C)')\n",
    "ax.set_title(img.attrs['long_name'])\n",
    "\n",
    "# f.savefig('./figures/pyplot_pcarree.jpg')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src='./figures/pyplot_pcarree.jpg'>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "How about `proplot`? (The combined colormap is shown too!)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# create our own colormap first\n",
    "import proplot as plot\n",
    "\n",
    "ir_br = plot.Colormap('spectral_r', 'grays',\n",
    "                      ratios=(1, 1), name='ir_br',\n",
    "#                       save=True,\n",
    "                      )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 5.25 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# %%capture\n",
    "\n",
    "# set axis\n",
    "f, axs = plot.subplots(projection=crs)\n",
    "axs.format(geogrid=False)\n",
    "\n",
    "# plot data\n",
    "m = axs.pcolormesh(img-273.15, transform=crs, cmap=ir_br, levels=256)\n",
    "\n",
    "# set others\n",
    "axs.colorbar(m, loc='r', label='Brightness Temperature ($^\\circ$C)')\n",
    "axs.set_title(img.attrs['long_name'])\n",
    "\n",
    "# f.savefig('./figures/proplot_crs.jpg')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src='./figures/proplot_crs.jpg'>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you prefer 'pure' image, it's also possible:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 4.83 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# %%capture\n",
    "\n",
    "# set axis\n",
    "f, axs = plot.subplots(projection=crs)\n",
    "axs.format(geogrid=False, linewidth=0)\n",
    "f.patch.set_visible(False)\n",
    "\n",
    "# plot data\n",
    "m = axs.pcolormesh(img-273.15, transform=crs, cmap=ir_br, levels=256)\n",
    "\n",
    "# set others\n",
    "axs.format(title='')\n",
    "\n",
    "# f.savefig('./figures/proplot_crs_noborder.jpg')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src='./figures/proplot_crs_noborder.jpg'>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "More scientific figure:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 5.73 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# %%capture\n",
    "\n",
    "# set axis\n",
    "f, axs = plot.subplots(proj='pcarree')\n",
    "axs.format(labels=True,\n",
    "           lonlines=10,\n",
    "           latlines=5,\n",
    "           lonlim=(lon.min(), lon.max()),\n",
    "           latlim=(lat.min(), lat.max()),\n",
    "           geogridlinewidth=0.5\n",
    "           )\n",
    "\n",
    "# plot data\n",
    "m = axs.pcolormesh(lon, lat, img-273.15, transform=ccrs.PlateCarree(), cmap=ir_br, levels=256)\n",
    "\n",
    "# set others\n",
    "axs.format(title=img.attrs['long_name'])\n",
    "cb = axs.colorbar(m, loc='r', label='Brightness Temperature ($^\\circ$C)')\n",
    "\n",
    "# f.savefig('./figures/proplot_pcarree.jpg')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src='./figures/proplot_pcarree.jpg'>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Of course, we can set the limit of colorbar by ourself:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 5.11 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# %%capture\n",
    "\n",
    "# set axis\n",
    "f, axs = plot.subplots(proj='pcarree')\n",
    "axs.format(labels=True,\n",
    "           lonlines=10,\n",
    "           latlines=5,\n",
    "           lonlim=(lon.min(), lon.max()),\n",
    "           latlim=(lat.min(), lat.max()),\n",
    "           geogridlinewidth=0.5\n",
    "           )\n",
    "\n",
    "\n",
    "# set levels\n",
    "cb_levels = plot.arange(-90, 30, 10)\n",
    "\n",
    "# plot data\n",
    "m = axs.pcolormesh(lon, lat, img-273.15,\n",
    "                   cmap=ir_br,\n",
    "                   vmin=-90, vmax=30,\n",
    "                   levels=256)\n",
    "\n",
    "# set others\n",
    "axs.format(title=img.attrs['long_name'])\n",
    "axs.colorbar(m, loc='r', values=cb_levels, label='Brightness Temperature ($^\\circ$C)')\n",
    "\n",
    "# f.savefig('./figures/proplot_pcarree_levels.jpg')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src='./figures/proplot_pcarree_levels.jpg'>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. `enhancement` method"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Add the configuration to `$PPP_CONFIG_DIR/enhancements/<sencor>.yaml` first.\n",
    "\n",
    "I will use `agri` as an example below:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here's the content of `agri.yaml`:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "enhancements:\n",
    "  AGRI_C12:\n",
    "    name: C12\n",
    "    operations:\n",
    "      - name: colorize\n",
    "        method: &colorizefun !!python/name:satpy.enhancements.colorize ''\n",
    "        kwargs:\n",
    "          palettes:\n",
    "            - {colors: spectral, min_value: 183.15, max_value: 253.15}\n",
    "            - {colors: greys, min_value: 253.15, max_value: 303.15}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some explanations can be found in this [issue](https://github.com/pytroll/satpy/issues/459) of satpy repository.\n",
    "I just mention some important things here:\n",
    "\n",
    "1. The filename should be <sensor>.yaml in case you mess up something;\n",
    "2. `standard_name` should be set correctly;\n",
    "    > Note that if you removed the first `name:` part then the enhancement would be used for all datasets matching standard_name.\n",
    "    > \n",
    "    > If you remove `standard_name` it would match for only datasets matching the exact name.\n",
    "    > \n",
    "    > If you have both it must match both of those items.\n",
    "    > \n",
    "    > You could accomplish the same thing in generic.yaml by specifying sensor: abi in addition to name and/or standard_name."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, let's read the data and apply our own colormap to it:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let make the figure more beautiful by adding colorbar:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "E:\\miniconda3\\envs\\satpy\\lib\\site-packages\\dask\\core.py:119: RuntimeWarning: invalid value encountered in greater_equal\n",
      "  return func(*args2)\n",
      "E:\\miniconda3\\envs\\satpy\\lib\\site-packages\\dask\\core.py:119: RuntimeWarning: invalid value encountered in less_equal\n",
      "  return func(*args2)\n"
     ]
    }
   ],
   "source": [
    "# set the corresponding colormap ticks range\n",
    "greys.set_range(-40, 30)\n",
    "spectral.set_range(-90, -40)\n",
    "\n",
    "# set the right width and height for colorbar\n",
    "height, width = lekima_scene[channel].shape\n",
    "h_legend = int(height/20)\n",
    "w_legend = int(width/2)\n",
    "\n",
    "# save dataset to image\n",
    "lekima_scene.save_datasets(base_dir = './figures/',\n",
    "                           filename='enhancement.png',\n",
    "                           compute = True,\n",
    "                           datasets = [channel],\n",
    "                           writer = 'simple_image',\n",
    "                           decorate={'decorate': [\n",
    "                                    {'scale': {'colormap': spectral, 'extend': False,\n",
    "                                               'width': w_legend, 'height': h_legend,\n",
    "                                               'tick_marks': 5, 'minor_tick_marks': 1,\n",
    "                                               'cursor': [0, 0], 'bg':'white',\n",
    "                                                # title settings\n",
    "                                                'title':'Brightness Temperature',\n",
    "                                                'fontsize': h_legend*10, 'align': [w_legend, 0],\n",
    "                                    }},\n",
    "                                    {'scale': {'colormap': greys, 'extend': False,\n",
    "                                               'width': w_legend, 'height': h_legend,\n",
    "                                               'cursor': [w_legend, 0],\n",
    "                                    }},\n",
    "                        ]\n",
    "                     }\n",
    "                 )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you got the TypeError when setting the title of colorbar:\n",
    "```\n",
    "TypeError: text() argument 2 must be Font, not None\n",
    "```\n",
    "Please fix this issue by adding \"check for font object\" in \"title\" section, as mentioned in this [pull](https://github.com/pytroll/pydecorate/pull/9)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src='./figures/enhancement.png'>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
